package datastructure.bst;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class BST<E extends Comparable<E>> {

    // 二分搜索树
    // 定义私有内部类,定义树节点
    private class Node {
        public E e;
        public Node left, right;

        public Node(E e) {
            this.e = e;
            left = null;
            right = null;
        }
    }

    public Node root;
    public int size;

    public BST() {
        root = null;
        size = 0;
    }

    // 判断是否为空
    public boolean isEmpty() {
        return size == 0;
    }

    // 获取元素个数
    public int getSize() {
        return size;
    }

    // 添加元素 使用递归,终止条件
    public void add(E e) {
        // 如果没有元素直接插入到根节点

        // 有元素的话,每一个元素都有子节点这样的话,我们就需要书写一个方法进行专门的插入操作.
        root = add(root, e);
    }

    private Node add(Node node, E e) {

        // 递归条件的简化,上面没有遍历到根节点,所以我们需要将其遍历到根节点
        if (node == null) {
            size++;
            return new Node(e);
        }

        // 进行问题缩小化
        if (e.compareTo(node.e) < 0) {
            node.left = add(node.left, e);
        } else if (e.compareTo(node.e) > 0) {
            node.right = add(node.right, e);
        }

        return node;
//这里并没有遍历到根节点，一个null节点也是一个
//        if (e.compareTo(node.e) < 0 && node.left == null) {
//            node.left = new Node(e);
//            return ;
//        } else if (e.compareTo(node.e) > 0 && node.right == null) {
//            node.right = new Node(e);
//            return;
//        }
//        if (e.compareTo(node.e) < 0 ) {
//            add(node.left, e);
//        } else {
//            add(node.right, e);
//        }

        // 当根节点不为空的时候,我们需要返回以原来节点为根节点

    }

    // 二分搜索树的查询
    public boolean contains(E e) {
        return contains(root, e);
    }

    // 查询Node为根节点的树种是否包含元素
    private boolean contains(Node node, E e) {
        // 中指条件当查询到叶子节点或者该书中没有节点时候推出
        if (node == null) {
            return false;
        }
        // 找到元素的时候返回
        if (node.e.equals(e)) {
            return true;
        } else if (e.compareTo(node.e) < 0) {
            // 如果e比跟节点小,查询左子树是否包含返回
            return contains(node.left, e);
        } else {// 大 ,查询右子树
            return contains(node.right, e);
        }
    }

    // 前序遍历
    public int preOrder() {
        return preOrder(root, 0);
    }

    // 以Node节点为跟节点开始,进行遍历
    private int preOrder(Node node, int deepth) {
        // 终止条件,遍历到叶子节点没有左右子树
        if (node == null) {
            return deepth;
        }

        System.out.println(node.e);
        // 前序遍历先访问跟节点在访问左右子树
        preOrder(node.left, deepth++);
        preOrder(node.right, deepth++);
        return deepth;
    }

    // 前序遍历非递归实现 ,使用栈实现
    public void preOrderNR() {
        Stack<Node> stack = new Stack<>();
        // 将跟节点压入栈
        stack.push(root);
        while (!stack.isEmpty()) {
            // 栈不为null时候,将栈顶元素取出
            Node cur = stack.pop();
            System.out.println(cur.e);
            // 将栈顶元素的右子树压入栈顶
            if (cur.right != null) {
                stack.push(cur.right);
            }
            if (cur.left != null) {
                stack.push(cur.left);
            }
        }
    }

    // 中序遍历
    public void inOrder() {
        inOrder(root);
    }

    private void inOrder(Node node) {
        if (node == null) {
            return;
        }
        // 先遍历左子树,节点,右子树
        inOrder(node.left);
        System.out.println(node.e);
        inOrder(node.right);
    }

    // 后续遍历
    public void postOrder() {
        postOrder(root);
    }

    private void postOrder(Node node) {
        if (node == null) {
            return;
        }
        // 先遍历左子树,节点,右子树
        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.e);
    }

    // 层序遍历(广度优先遍历) --适用于查询某一个值节点
    public void levelOrder() {
        Queue<Node> q = new LinkedList<>();
        q.add(root);
        while (!q.isEmpty()) {
            // 队列由于是先进先出,我们将需要将取出来的元素的左右子树方进队列中
            Node cur = q.remove();
            System.out.println(cur.e);
            if (cur.left != null) {
                q.add(cur.left);
            }
            if (cur.right != null) {
                q.add(cur.right);
            }
        }
    }

    // 获取最小值一直向左到没有做节点
    public E miniNum() {
        if (size == 0) {
            throw new IllegalAccessError("为空");
        }
        Node node = miniNum(root);
        return node.e;
    }

    private Node miniNum(Node node) {
        if (node.left == null) {
            return node;
        }
        Node num = miniNum(node.left);
        return num;
    }

    // 获取最大值一直向右到没有右节点
    public E maxNum() {
        if (size == 0) {
            throw new IllegalAccessError("为空");
        }
        return maxNum(root).e;
    }

    private Node maxNum(Node node) {
        if (node.right == null) {
            return node;
        }
        return maxNum(node.right);

    }

    public E removeMiniNum() {
        E res = miniNum();
        // 找到最小元素进行删除
        root = removeMiniNum(root);
        return res;
    }

    private Node removeMiniNum(Node node) {
        if (node.left == null) {
            Node nodeRight = node.right;
            node.right = null;
            size--;
            return nodeRight;
        }

        node.left = removeMiniNum(node.left);

        return node;
    }

    public E removeMaxNum() {
        E res = maxNum();
        // 找到最大元素进行删除
        root = removeMaxNum(root);
        return res;
    }

    private Node removeMaxNum(Node node) {
        if (node.right == null) {
            Node nodeLeft = node.left;
            node.right = null;
            size--;
            return nodeLeft;
        }
        node.right = removeMaxNum(node.right);
        return node;
    }

    // 删除任一节点元素
    public void remove(E e) {
        root = remove(root, e);
    }

    private Node remove(Node node, E e) {
        // 如果是根元素或者node为null时候直接返回
        if (node == null) {
            return null;
        }

        if (e.compareTo(node.e) < 0) {
            node.left = remove(node.left, e);
            return node;
        } else if (e.compareTo(node.e) > 0) {
            node.right = remove(node.right, e);
            return node;
        } else { // 相等
            //只有右子树
            if (node.left == null) {
                // 将右子树存放并返回
                Node rightNode = node.right;
                node.right = null;
                size--;
                return rightNode;
            }
            //只有左子树
            if (node.right == null) {
                // 将左子树存放并返回
                Node leftNode = node.left;
                node.left = null;
                size--;
                return leftNode;
            }

            // 如果同时拥有左右子树就需要找到后继. 右子树中最小元素,            前驱为左子树中最大元素
            Node successor = miniNum(node.right);
            // 删除最小元素
            successor.right = removeMiniNum(node.right);
            successor.left = node.left;
            // 释放原来node节点
            node.left = node.right = null;
            return successor;
        }
    }

}
